EDGE ~ level.bin

Level Format

// @MyGodStudio has pointed out a few errors in this documentation.
// I will amend these once I'm more certain about them.

#define TIME_THRESHOLDS_LENGTH 5

struct edge_level {
    level_header header;    // quick access to data used for the level-select screen
    char size_z;
    short size_x;
    short size_y;
    short unknown_short_1;  // size_x + size_y
    short unknown_short_2;  // size_x + size_y + (2 * size_z)
    short unknown_short_3;  // (unknown_short_1 + 9) / 10
    short unknown_short_4;  // (unknown_short_2 + 9) / 10
    char unknown_byte_1;    // 10
    short unknown_short_5;  // size_y - 1
    short unknown_short_6;  // 0
    char legacy_minimap[];   // length = ((unknown_short_3 * unknown_short_4) + 7) / 8
    char collision_map[];    // length = size_z * (((size_x * size_y) + 7) / 8)
    vector spawn_point;
    short zoom;
    // if zoom < 0
        short fov;
        bool auto_adjust_zoom_for_fov;
    // endif
    vector exit_point;
    short moving_platform_count;
    moving_platform moving_platforms[moving_platform_count];
    short bumper_count;
    bumper bumpers[bumper_count];
    short falling_platform_count;
    falling_platform falling_platforms[falling_platform_count];
    short checkpoint_count;
    checkpoint checkpoints[checkpoint_count];
    short camera_trigger_count;
    camera_trigger camera_triggers[camera_trigger_count];
    short prism_count;
    prism prisms[prism_count];
    short fans_count;       // deprecated, presumably would have been followed by fan fans[fans_count];
    short block_event_count;
    block_event block_events[block_event_count];
    short button_count;
    button buttons[button_count];
    short othercube_count;
    othercube othercubes[othercube_count];
    short resizer_count;
    resizer resizers[resizer_count];
    short mini_blocks_count;    // deprecated, presumably would have been followed by mini_block mini_blocks[mini_blocks_count];
    char theme;
    char music_j2me;
    char music;
};

struct level_header {
    int level_id;
    int title_length;
    char title[title_length];
    short time_thresholds[TIME_THRESHOLDS_LENGTH];
    short prisms_count;
};

struct vector {
    short x;
    short y;
    short z;
};

struct moving_platform {
    bool auto_start;
    bool looped;
    short clones;   // deprecated. set to zero.
    bool full_block;
    char waypoints_count;
    waypoint waypoints[waypoints_count];
};

struct waypoint {
    vector position;
    short travel_time;
    short pause_time;
};

struct bumper {
    bool auto_start;
    vector position;
    bumper_side north;      // assuming north as -Y in blockspace, top-right in screenspace
    bumper_side east;
    bumper_side south;
    bumper_side west;
};

struct bumper_side {
    short start_delay;
    short pulse_rate;
};

struct falling_platform {
    vector position;
    short float_time;
};

struct checkpoint {
    vector position;
    short respawn_offset_z;
    char radius_x;
    char radius_y;
};

struct camera_trigger {
    vector position;
    short zoom;
    char radius_x;
    char radius_y;
    // if zoom == -1
        bool reset;
        short start_delay;
        short duration;
        short value;
        bool single_use;
        bool value_is_fov;      // value is zoom level if false
    // endif
};

struct prism {
    vector position;
    char energy;    // deprecated. put a zero or something.
};

struct block_event {
    char type;
    short block_id;
    short payload;
    /*
        type == 0:
            affects moving_platforms[block_id]
            payload == 0:
                traverse all waypoints
            payload != 0:
                traverse `payload` waypoints.
        type == 1:
            affects bumpers[block_id]
            payload == 0:
                if bumper is running, stop it
                else fire it once
            payload == 1:
                start the bumper and enable looping
        type == 2:
            triggers achievements.
            block_id is the achievement ID
            payload is additional metadata that varies between different achievements.
        type == 3:
            affects buttons[block_id]
            payload == 0:
                enable the button (pop it up)
            payload == 1:
                disable the button
    */
};

struct button {
    char visibility;
        // visibility == 0: invisible
        // visibility == 1: visible, solid
        // visibility == 2: visible, ghosted
    char press_count;   // after a button has been pressed `press_count` times, it cannot be re-enabled by an event.
            // press_count = 0 can be re-enabled as many times as you like.
    char mode;
        // mode == 0: reverses the event when the button is released
        // mode == 1: event is permanent, button stays up when released
        // mode == 2: event is permanent, button stays down when released
    short parent_id;
    bool sequence_in_order;
    byte siblings_count;
    bool is_moving;
    // if is_moving
        short moving_block_id;
    // else
        vector position;
    // endif
    short event_count;
    short events[event_count];
    /*
        this is a tricky one so I feel it needs to be explained.
        a standalone button uses
            visibility
            press_count
            mode
            is_moving (and related position system)
            event_count
            events

        a button sequence uses all of those and more.
        a button sequence consists of multiple buttons which when all pressed will activate a collection of events.
        a button sequence can insist that the buttons be pressed in a particular order.
        a button sequence has a 'parent' button and a series of 'child' buttons.
        only the parent trigger should have events tied to it.
        the parent and children should all have these properties:
            sequence_in_order = 
            mode = 2
        the parent has these properties:
            parent_id = -1 (default)
            siblings_count = 
            events = 
        the children have these properties:
            parent_id = 
            siblings_count = 0
    */
};

struct othercube {
    vector position_trigger;
    short moving_block_sync;    // id of a looped moving block to sync to. -1 for no sync.
    // if moving_block_sync == -2 (then it's a dark cube)
        char darkcube_radius_x;
        char darkcube_radius_y;
        short darkcube_moving_block_sync;
    // endif
    short key_event_count;
    vector position_cube;
    key_event key_events[key_event_count];  // interesting that this isn't immediately after its length...
};

struct key_event {
    short time_offset;
    char direction;
        // direction == 0: west
        // direction == 1: east
        // direction == 2: north
        // direction == 3: south
        // assuming, as earlier, north to be -Y in blockspace, top-right in screenspace
    char event_type;
        // event_type == 0: key down
        // event_type == 1: key up
};

struct resizer {
    vector position;
    bool visible;
    char direction;
        // direction == 0: shrink
        // direction == 1: grow
};